﻿#include <sstream>
#include <CXXLXMLCOMPOSITE.HPP>
#include <CXXLWCSPBRK.HPP>

using namespace CxxlMan;
using namespace std;

typedef cxxlComposite<string_wrapper<wchar_t>,true> XmlAttr;

/********************************
** class cxxlXmlComposite
********************************/

// Constructor
cxxlXmlComposite::cxxlXmlComposite(const UNICODE_String &idName, ISpirit *spirit)
  :cxxlObject(spirit),cxxlComposite(idName,spirit)
{
}


// 設定屬性質
void cxxlFASTCALL cxxlXmlComposite::SetAttr(const UNICODE_String &Value, const UNICODE_String &Name)
{
  if(this->GetName().StrLength() == 0 || Name.isNULL() || Name.StrLength() == 0)
    return ;

  csObject.Enter();

  Smart_Ptr<XmlAttr> XmlAttr_Ptr = GetObj();
  if(XmlAttr_Ptr.isNULL())
  {
    XmlAttr_Ptr = new XmlAttr(L"XmlAttr",GetSpirit());
    SetObj(XmlAttr_Ptr);
  }

  csObject.Leave();

  XmlAttr_Ptr->Delete(XmlAttr_Ptr->GetComposite(Name));
  XmlAttr_Ptr->Add(Value, Name);
}

// 取得屬性質
UNICODE_String cxxlFASTCALL cxxlXmlComposite::GetAttr(const UNICODE_String &Name) const
{
  Smart_Ptr<XmlAttr> XmlAttr_Ptr = GetObj();
  if(XmlAttr_Ptr.isNULL())
    return UNICODE_String((wchar_t *)NULL);

  Smart_Ptr<string_wrapper<wchar_t> > tmp = XmlAttr_Ptr->GetObj(Name);
  return (string_wrapper<wchar_t> *)tmp;
}

Smart_Ptr<cxxlList<XmlAttr_li> > cxxlFASTCALL cxxlXmlComposite::GetAttrList() const
{
  Smart_Ptr<cxxlList<XmlAttr_li> > XmlAttrTable_Ptr(new cxxlList<XmlAttr_li>);

  Smart_Ptr<XmlAttr > XmlAttres_Ptr = GetObj();
  if(XmlAttres_Ptr.isNULL() == false)
  {
    Smart_Ptr<cxxlList<XmlAttr> > XmlAttr_List = XmlAttres_Ptr->cxxlList_Create();

    XmlAttr_List->ResetPT(toHead);
    for(Smart_Ptr<XmlAttr > XmlAttr_Ptr = (*XmlAttr_List)++; XmlAttr_Ptr.isNULL() == false; XmlAttr_Ptr = (*XmlAttr_List)++)
    {
      XmlAttr_li *XT = new XmlAttr_li;
      XT->Name = XmlAttr_Ptr->GetName();
      XT->Attr = XmlAttr_Ptr->GetObj();
      XmlAttrTable_Ptr->Push_Back(XT);
    }
  }
  return XmlAttrTable_Ptr;
}

Smart_Ptr<cxxlXml_Node> cxxlFASTCALL cxxlXmlComposite::ConvertToNode()
{
  return NULL;
}

Smart_Ptr<cxxlXml_Content> cxxlFASTCALL cxxlXmlComposite::ConvertToContent()
{
  return NULL;
}

UNICODE_String cxxlFASTCALL cxxlXmlComposite::GetName() const
{
  return cxxlComposite::GetName();
}


/********************************
** class cxxlXml_Content
********************************/

cxxlXml_Content::cxxlXml_Content(const UNICODE_String &idName, ISpirit *spirit)
  :cxxlObject(spirit),cxxlXmlComposite(idName, spirit)
{

}

void cxxlFASTCALL cxxlXml_Content::SetContent(const UNICODE_String &Content)
{
  csObject.Enter();

  m_Content = Content;

  csObject.Leave();
}

UNICODE_String cxxlFASTCALL cxxlXml_Content::GetContent() const
{
  CriticalSecHandle AutoCSH(csObject);

  return m_Content;
}

Smart_Ptr<cxxlXml_Content> cxxlFASTCALL cxxlXml_Content::ConvertToContent()
{
  return Smart_Ptr<cxxlXml_Content>(this);
}


/********************************
** class cxxlXml_Node
********************************/

static const UNICODE_String Naming(const UNICODE_String &idName)
{
  if(idName.isNULL() || idName.StrLength() == 0)
    return UNICODE_String(L"root");
  else
    return idName;
}

cxxlXml_Node::cxxlXml_Node(const UNICODE_String &idName, ISpirit *spirit)
  :cxxlObject(spirit),cxxlXmlComposite(Naming(idName), spirit)
{

}

cxxlXmlComposite * cxxlFASTCALL cxxlXml_Node::CreateSelf(UNICODE_String idName,ISpirit *spirit) const
{
  return pcxxlXmlComposite;
}


Smart_Ptr<cxxlXml_Node> cxxlFASTCALL cxxlXml_Node::GetParent() const
{
  //return Smart_Cast<cxxlXml_Node>(cxxlComposite::GetParent());
  return (cxxlXml_Node*)(cxxlComposite*)(cxxlComposite::GetParent());
}


Smart_Ptr<cxxlXml_Node> cxxlFASTCALL cxxlXml_Node::AddNode(const UNICODE_String &Name)
{
  if(Name.isNULL() || Name.StrLength() == 0)
    return NULL;

  CriticalSecHandle AutoCSH(csObject);
  pcxxlXmlComposite = new cxxlXml_Node(Name,GetSpirit());
  //return Smart_Cast<cxxlXml_Node>(cxxlComposite::Add(NULL,Name));
  return (cxxlXml_Node*)(cxxlComposite*)(cxxlComposite::Add(NULL,Name));
}

Smart_Ptr<cxxlXml_Node> cxxlFASTCALL cxxlXml_Node::AddPrevNode(const UNICODE_String &Name, const Smart_Ptr<cxxlXmlComposite> &Node)
{
  if(Name.isNULL() || Name.StrLength() == 0)
    return NULL;

  CriticalSecHandle AutoCSH(csObject);
  pcxxlXmlComposite = new cxxlXml_Node(Name,GetSpirit());
  //return Smart_Cast<cxxlXml_Node>(cxxlComposite::AddPrev(NULL,Name,(cxxlXmlComposite *)Node));
  return (cxxlXml_Node*)(cxxlComposite*)cxxlComposite::AddPrev(NULL,Name,(cxxlXmlComposite *)Node);
}

Smart_Ptr<cxxlXml_Node> cxxlFASTCALL cxxlXml_Node::AddNextNode(const UNICODE_String &Name, const Smart_Ptr<cxxlXmlComposite> &Node)
{
  if(Name.isNULL() || Name.StrLength() == 0)
    return NULL;

  CriticalSecHandle AutoCSH(csObject);
  pcxxlXmlComposite = new cxxlXml_Node(Name,GetSpirit());
  //return Smart_Cast<cxxlXml_Node>(cxxlComposite::AddNext(NULL,Name,(cxxlXmlComposite *)Node));
  return (cxxlXml_Node*)(cxxlComposite*)cxxlComposite::AddNext(NULL,Name,(cxxlXmlComposite *)Node);
}


Smart_Ptr<cxxlXml_Content> cxxlFASTCALL cxxlXml_Node::AddContent(const UNICODE_String &Name)
{
  if(Name.isNULL())
    return NULL;

  CriticalSecHandle AutoCSH(csObject);
  pcxxlXmlComposite = new cxxlXml_Content(Name,GetSpirit());

  //return Smart_Cast<cxxlXml_Content>(cxxlComposite::Add(NULL,Name));
  return (cxxlXml_Content*)(cxxlComposite*)cxxlComposite::Add(NULL,Name);
}

Smart_Ptr<cxxlXml_Content> cxxlFASTCALL cxxlXml_Node::AddPrevContent(const UNICODE_String &Name, const Smart_Ptr<cxxlXmlComposite> &Node)
{
  if(Name.isNULL())
    return NULL;

  CriticalSecHandle AutoCSH(csObject);
  pcxxlXmlComposite = new cxxlXml_Content(Name,GetSpirit());
  //return Smart_Cast<cxxlXml_Content>(cxxlComposite::AddPrev(NULL,Name,(cxxlXmlComposite *)Node));
  return (cxxlXml_Content*)(cxxlComposite*)(cxxlComposite::AddPrev(NULL,Name,(cxxlXmlComposite *)Node));
}

Smart_Ptr<cxxlXml_Content> cxxlFASTCALL cxxlXml_Node::AddNextContent(const UNICODE_String &Name, const Smart_Ptr<cxxlXmlComposite> &Node)
{
  if(Name.isNULL())
    return NULL;

  CriticalSecHandle AutoCSH(csObject);
  pcxxlXmlComposite = new cxxlXml_Content(Name,GetSpirit());
  //return Smart_Cast<cxxlXml_Content>(cxxlComposite::AddNext(NULL,Name,(cxxlXmlComposite *)Node));
  return (cxxlXml_Content*)(cxxlComposite*)(cxxlComposite::AddNext(NULL,Name,(cxxlXmlComposite *)Node));
}

Smart_Ptr<cxxlList<cxxlXmlComposite> > cxxlFASTCALL cxxlXml_Node::GetSubnodes() const
{
  Smart_Ptr<cxxlList<cxxlComposite<XmlAttr,false> > > cxxlComposite_List = cxxlList_Create();
  Smart_Ptr<cxxlList<cxxlXmlComposite> > cxxlXmlComposite_List(new cxxlList<cxxlXmlComposite>(GetSpirit()));

  cxxlComposite_List->ResetPT(toHead);
  for(Smart_Ptr<cxxlComposite<XmlAttr,false> > cxxlComposite_Ptr = (*cxxlComposite_List)++ ;
    cxxlComposite_Ptr.isNULL() == false;
    cxxlComposite_Ptr = (*cxxlComposite_List)++)
  {
    //Smart_Ptr<cxxlXmlComposite> cxxlXmlComposite_Ptr = Smart_Cast<cxxlXmlComposite>(cxxlComposite_Ptr);
    Smart_Ptr<cxxlXmlComposite> cxxlXmlComposite_Ptr = (cxxlXmlComposite*)(cxxlComposite*)(cxxlComposite_Ptr);
    cxxlXmlComposite_List->Push_Back(cxxlXmlComposite_Ptr);
  }

  return cxxlXmlComposite_List;
}

Smart_Ptr<cxxlXml_Node> cxxlFASTCALL cxxlXml_Node::ConvertToNode()
{
  return Smart_Ptr<cxxlXml_Node>(this);
}

/********************************
** ExportXML()
********************************/

class XmlBuildStr
{
  unsigned int Indent; // 縮排層數
  wostream &XmlStr; // 回報成果

  void cxxlFASTCALL doIndent()
  {
    wstring ws_space(Indent*2,L' ');
    XmlStr << ws_space.c_str();
  }

  UNICODE_String cxxlFASTCALL NormalName(const wchar_t *Name)
  {
    static const wchar_t *Sh[] = {L"<",L">",L"&",L"'",L"\"", L"\t",L" ",L"\xd",L"\xa",L"=",L"/",L"?",NULL};
    static const wchar_t *Rp[] = {L"&lt;",L"&gt;",L"&amp;",L"&apos;",L"&quote;", L"&#09;", L"&#95;",L"&#13;",L"&#10;",L"&#61;",L"&#47;",L"&#63;",NULL};
    return cxxlWcsReplace(Name,Sh,Rp);
  }

  UNICODE_String cxxlFASTCALL NormalValue(const wchar_t *Value)
  {
    static const wchar_t *Sh[] = {L"<",L">",L"&",L"'",L"\"", L"\xd",L"\xa", L"\t", NULL};
    static const wchar_t *Rp[] = {L"&lt;",L"&gt;",L"&amp;",L"&apos;",L"&quote;", L"&#13;",L"&#10;",L"&#09;",NULL};

    UNICODE_String w = cxxlWcsReplace(Value,Sh,Rp);

    static const wchar_t *Space_Sh[] = {L" ",NULL};
    wostringstream strout;

    cxxlWcspbrk Wcspbrk(new UnicodeStr_Source((const wchar_t*)w));

    cxxlWcspbrk_XResult XR = Wcspbrk.XNext(Space_Sh);
    for(unsigned int i = 0; i < XR.SubStr.StrLength(); ++i)
      strout << L"&#95;";


    while(XR.isNULL == false)
    {
      cxxlWcspbrk_Result R = Wcspbrk.Next(Space_Sh);
      strout << (const wchar_t*)R.SubStr;

      if(R.Token.isNULL())
        break;

      XR = Wcspbrk.XNext(Space_Sh);

      if(XR.isNULL)
        strout << L"&#95;";
      else
        strout << L' ';

      for(unsigned int i = 0; i < XR.SubStr.StrLength(); ++i)
        strout << L"&#95;";
    }
    // return strout.str(); // 在 vs2008 這樣做會造成不定時非此處當掉，莫明其妙
    return strout.str().c_str();
  }

public:
  // Constructor
  XmlBuildStr(wostream &wout)
    :XmlStr(wout)
  {
    Indent = 0;
  }

  // Destructor
  ~XmlBuildStr()
  {
  }

  void cxxlFASTCALL AddNode(const wchar_t *Name)
  {
    doIndent();
    ++Indent;
    XmlStr << L'<' << (const wchar_t*)NormalName(Name);
  }

  void cxxlFASTCALL CloseNode()
  {
    XmlStr << L'>' << endl;
  }

  void cxxlFASTCALL CloseEndNode()
  {
    XmlStr << L"/>" << endl;
    --Indent;
  }

  void cxxlFASTCALL EndNode(const wchar_t *Name)
  {
    --Indent;
    doIndent();
    XmlStr << L"</" << (const wchar_t*)NormalName(Name) << L'>' << endl;
  }

  void cxxlFASTCALL AddAttr(const wchar_t *Name,const wchar_t *Value)
  {
    XmlStr << L' ' << (const wchar_t*)NormalName(Name) << L"=\"" << (const wchar_t*)NormalValue(Value) << L"\"";
  }

  void cxxlFASTCALL AddContent(const wchar_t *Name)
  {
    doIndent();
    XmlStr << L'<' << (const wchar_t*)NormalName(Name);
  }

  void cxxlFASTCALL AddContent()
  {
    doIndent();
  }

  void cxxlFASTCALL CloseContend()
  {
    XmlStr << L'>';
  }

  void cxxlFASTCALL SetContend(const wchar_t *Content)
  {
    XmlStr << (const wchar_t*)NormalValue(Content);
  }

  void cxxlFASTCALL EndContend(const wchar_t *Name)
  {
    XmlStr << L"</" << (const wchar_t*)NormalName(Name) << L'>' << endl;
  }

  void cxxlFASTCALL EndContend()
  {
    XmlStr << endl;
  }

};

class cxxlXmlCompositeReader
{
  XmlBuildStr *pXmlBuildStr;

  void cxxlFASTCALL XmlContentExport(const cxxlXml_Content *pContent)
  {
    UNICODE_String ContentName = pContent->GetName();
    if(ContentName.StrLength() > 0)
    {
      pXmlBuildStr->AddContent(ContentName);

      Smart_Ptr<cxxlList<XmlAttr_li> > XmlAttr_List = pContent->GetAttrList();
      if(XmlAttr_List->GetCount() > 0)
      {
        XmlAttr_List->ResetPT(toHead);
        for(Smart_Ptr<XmlAttr_li> XmlAttr_li_Ptr = (*XmlAttr_List)++;
            XmlAttr_li_Ptr.isNULL() == false;
            XmlAttr_li_Ptr = (*XmlAttr_List)++)
        {
          pXmlBuildStr->AddAttr(XmlAttr_li_Ptr->Name,XmlAttr_li_Ptr->Attr);
        }
      }
      pXmlBuildStr->CloseContend();
    }
    else
      pXmlBuildStr->AddContent();

    pXmlBuildStr->SetContend(pContent->GetContent());

    if(ContentName.StrLength() > 0)
      pXmlBuildStr->EndContend(ContentName);
    else
      pXmlBuildStr->EndContend();

  }

  void cxxlFASTCALL XmlNodeExport(const cxxlXml_Node *pNode)
  {
    pXmlBuildStr->AddNode(pNode->GetName());

    {
      Smart_Ptr<cxxlList<XmlAttr_li> > XmlAttr_List = pNode->GetAttrList();

      if(XmlAttr_List->GetCount() > 0)
      {
        XmlAttr_List->ResetPT(toHead);
        for(Smart_Ptr<XmlAttr_li> XmlAttr_li_Ptr = (*XmlAttr_List)++;
            XmlAttr_li_Ptr.isNULL() == false;
            XmlAttr_li_Ptr = (*XmlAttr_List)++)
        {
          pXmlBuildStr->AddAttr(XmlAttr_li_Ptr->Name,XmlAttr_li_Ptr->Attr);
        }
      }
    }

    Smart_Ptr<cxxlList<cxxlXmlComposite> > Subnodes_List = pNode->GetSubnodes();
    if(Subnodes_List->GetCount() > 0)
    {
      pXmlBuildStr->CloseNode();

      Subnodes_List->ResetPT(toHead);
      for(Smart_Ptr<cxxlXmlComposite> cxxlXmlComposite_Ptr = (*Subnodes_List)++;
          cxxlXmlComposite_Ptr.isNULL() == false;
          cxxlXmlComposite_Ptr = (*Subnodes_List)++)
      {
        Smart_Ptr<cxxlXml_Node> Node_Ptr = cxxlXmlComposite_Ptr->ConvertToNode();
        if(Node_Ptr.isNULL() == false)
          XmlNodeExport(Node_Ptr);
        else
          XmlContentExport( cxxlXmlComposite_Ptr->ConvertToContent() );
      }

      pXmlBuildStr->EndNode(pNode->GetName());
    }
    else
      pXmlBuildStr->CloseEndNode();
  }

public:
  cxxlXmlCompositeReader(wostream &wout, const cxxlXml_Node *pNode)
  {
    pXmlBuildStr = new XmlBuildStr(wout);

    XmlNodeExport(pNode);
  }

  ~cxxlXmlCompositeReader()
  {
    delete pXmlBuildStr;
  }

};

CXXL_DLLEXPORT void cxxlFASTCALL CxxlMan::ExportXML(wostream &wout, const Smart_Ptr<cxxlXml_Node> &Node)
{
  cxxlXmlCompositeReader Reader(wout, Node);
}


/********************************
** ImportXML()
********************************/

struct TagAttr:virtual public cxxlObject
{
  wstring AttrName;
  wstring Value;

  TagAttr(ISpirit *spirit)
    :cxxlObject(spirit)
  {
  }
};

struct Tag:virtual public cxxlObject
{
  wstring TagName;
  Smart_Ptr<cxxlList<TagAttr> > Attr_List;
  bool isCloseEnd; // 若是無內容標籤為 true

  Tag(ISpirit *spirit)
    :cxxlObject(spirit),Attr_List(new cxxlList<TagAttr>(spirit), this)
  {
  }
};

class XmlStrReader:virtual public cxxlObject
{

  cxxlWcspbrk Wcspbrk;

  // 處理過程中有錯誤設為 true
  bool err;
  bool cxxlFASTCALL isError() {return err;}

  // 讓 Wcspbrk_ref 略過空白的部份，有空白的部份被略過回覆 true
  bool cxxlFASTCALL SkipSpace(cxxlWcspbrk &Wcspbrk_ref);

  // 用來讓 Wcspbrk 讀取位置移到 XML 文件中根節點開始之處
  // 有錯誤會設定 err
  void cxxlFASTCALL root_filter();

  // NewXmlComposite();

  // 截取 Tag 閇始的部份，包含屬性
  // 有錯誤會設定 err
  Smart_Ptr<Tag> cxxlFASTCALL CatchTag();

  UNICODE_String cxxlFASTCALL UnNormalName(const wchar_t *Name)
  {
    static const wchar_t *Sh[] = {L"&lt;",L"&gt;",L"&amp;",L"&apos;",L"&quote;", L"&#09;",L"&#95;",L"&#13;",L"&#10;",L"&#61;",L"&#47;",L"&#63;",NULL};
    static const wchar_t *Rp[] = {L"<",L">",L"&",L"'",L"\"", L"\t",L" ",L"\xd",L"\xa",L"=",L"/",L"?",NULL};
    return cxxlWcsReplace(Name,Sh,Rp);
  }

  UNICODE_String cxxlFASTCALL UnNormalValue(const wchar_t *Value)
  {
    wistringstream strin(Value);
    wostringstream strout;

    wstring temp;

    strin >> temp;

    strout << temp;
    // temp.clear();

    while(strin >> temp)
    {
      strout << L' ';
      strout << temp;
    }

    static const wchar_t *Sh[] = {L"&lt;",L"&gt;",L"&amp;",L"&apos;",L"&quote;", L"&#13;",L"&#10;",L"&#95;",L"&#09;",NULL};
    static const wchar_t *Rp[] = {L"<",L">",L"&",L"'",L"\"", L"\xd",L"\xa",L" ",L"\t",NULL};
    return cxxlWcsReplace(strout.str().c_str(),Sh,Rp);
  }

  void cxxlFASTCALL AddNoNameContent(cxxlXml_Node *ParentNode,const wstring &S);

  void cxxlFASTCALL NewSubContent(cxxlXml_Node *ParentNode, const Smart_Ptr<Tag> &Tag_Ptr, const wstring &Content);
  void cxxlFASTCALL NewSubNode(cxxlXml_Node *ParentNode, const Smart_Ptr<Tag> &Tag_Ptr, wstring NoNameContent);
  Smart_Ptr<cxxlXml_Node> cxxlFASTCALL CreateSubNode(cxxlXml_Node *ParentNode, const Smart_Ptr<Tag> &Tag_Ptr);
  void cxxlFASTCALL NewSubNodeOrContent(cxxlXml_Node *ParentNode);

public:
  // Constructor
  XmlStrReader(wistream &XmlStr, ISpirit *spirit)
    :cxxlObject(spirit), Wcspbrk(new wiStream_Source(XmlStr), GetSpirit())
  {
    err = false;
  }

  // Destructor
  virtual ~XmlStrReader(){}

  // 將 XML 文件 XmlStr 轉換為 cxxlXmlComposite
  // 若失敗回覆 NULL
  Smart_Ptr<cxxlXml_Node> cxxlFASTCALL CV();
};

void cxxlFASTCALL XmlStrReader::AddNoNameContent(cxxlXml_Node *ParentNode,const wstring &S)
{
  UNICODE_String unv = UnNormalValue(S.c_str());
  if(unv.StrLength())
  {
    Smart_Ptr<cxxlXml_Content> Content_Ptr = ParentNode->AddContent(L"");
    Content_Ptr->SetContent( unv );
  }
}

Smart_Ptr<Tag> cxxlFASTCALL XmlStrReader::CatchTag()
{
  if(SkipSpace(Wcspbrk))
  {
    err = true;
    return NULL;
  }

  Smart_Ptr<Tag> Tag_Ptr(new Tag(this->GetSpirit()));

  static const wchar_t *Sh[] = {L" ", L"\t", L"\r\n", L"\n\r", L"\r", L"\n", L">", L"/>", L"?", L"/", L"<", L"=",L"\"", L"'", NULL};
  cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);
  Tag_Ptr->TagName = R.SubStr;

  if(R.SubStr.StrLength() == 0 || R.Token.isNULL() || R.Token == L"<" || R.Token == L"=" || R.Token == L"\"", R.Token == L"'", R.Token == L"/", R.Token == L"?")
  {
    err = true;
    return NULL;
  }
  else if(R.Token == L"/>")
  {
    Tag_Ptr->isCloseEnd = true;
    return Tag_Ptr;
  }
  else if(R.Token == L">")
  {
    Tag_Ptr->isCloseEnd = false;
    return Tag_Ptr;
  }

  while(true)
  {
    Smart_Ptr<TagAttr> Attr_Ptr(new TagAttr(this->GetSpirit()));

    SkipSpace(Wcspbrk);
    cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);
    Attr_Ptr->AttrName = R.SubStr;

    if(R.Token.isNULL() || R.Token == L"<" || R.Token == L"\"", R.Token == L"'" || R.Token == L"/")
    {
      err = true;
      return NULL;
    }
    else if(R.Token == L"/>")
    {
      if(R.SubStr.StrLength() != 0)
      {
        err = true;
        return NULL;
      }
      Tag_Ptr->isCloseEnd = true;
      return Tag_Ptr;
    }
    else if(R.Token == L">")
    {
      if(R.SubStr.StrLength() != 0)
      {
        err = true;
        return NULL;
      }
      Tag_Ptr->isCloseEnd = false;
      return Tag_Ptr;
    }
    else if(R.Token != L"=") // 空白
    {
      static const wchar_t *Sh[] = {L"=", NULL};
      SkipSpace(Wcspbrk);
      cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);

      if(R.SubStr.StrLength() != 0 || R.Token.isNULL())
      {
        err = true;
        return NULL;
      }
    }
    // else if(R.Token == L"=")


    static const wchar_t *Sh[] = {L"\"", L"'",NULL};
    SkipSpace(Wcspbrk);
    R = Wcspbrk.Next(Sh);

    if(R.SubStr.StrLength() != 0 || R.Token.isNULL())
    {
      err = true;
      return NULL;
    }
    else if(R.Token == L"\"")
    {
      static const wchar_t *Sh[] = {L">", L"<", L"\"", NULL};
      cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);

      if(R.Token.isNULL() || R.Token == L"<" || R.Token == L">")
      {
        err = true;
        return NULL;
      }

      Attr_Ptr->Value = R.SubStr;
    }
    else // if(R.Token == L"'")
    {
      static const wchar_t *Sh[] = {L">", L"<", L"'", NULL};
      cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);

      if(R.Token.isNULL() || R.Token == L"<" || R.Token == L">")
      {
        err = true;
        return NULL;
      }

      Attr_Ptr->Value = R.SubStr;
    }

    Tag_Ptr->Attr_List->Push_Back(Attr_Ptr);
  }
}

bool cxxlFASTCALL XmlStrReader::SkipSpace(cxxlWcspbrk &Wcspbrk_ref)
{
  static const wchar_t *Sh[] = {L" ", L"\t", L"\r\n", L"\n\r", L"\r", L"\n", NULL};

  cxxlWcspbrk_XResult R = Wcspbrk_ref.XNext(Sh);

  if(R.SubStr.StrLength() != 0)
    return true;
  else
    return false;
}


void cxxlFASTCALL XmlStrReader::root_filter()
{
  static const wchar_t *root_Sh[] = {L"<!--",L"<?",L"<",NULL};

  while(true)
  {
    SkipSpace(Wcspbrk);
    cxxlWcspbrk_Result R = Wcspbrk.Next(root_Sh);

    if(R.Token.isNULL() || R.SubStr.StrLength() > 0)
    {
      err = true;
      return;
    }

    else if(R.Token == L"<")
    {
      return;
    }
    else if(R.Token == L"<?")
    {
      const wchar_t *Sh[] = {L"?>",NULL};
      cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);
      if(R.Token.isNULL())
      {
        err = true;
        return;
      }
      continue;
    }
    else
    {
      const wchar_t *Sh[] = {L"-->",NULL};
      cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);
      if(R.Token.isNULL())
      {
        err = true;
        return;
      }
      continue;
    }
  }
}

void cxxlFASTCALL XmlStrReader::NewSubContent(cxxlXml_Node *ParentNode, const Smart_Ptr<Tag> &Tag_Ptr, const wstring &Content)
{
  const wchar_t *Sh[] = {L">",NULL};
  SkipSpace(Wcspbrk);
  cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);
  if(R.Token.isNULL() || R.SubStr.StrLength() > 0)
  {
    err = true;
    return;
  }

  Smart_Ptr<cxxlXml_Content> Content_Ptr = ParentNode->AddContent( UnNormalName(Tag_Ptr->TagName.c_str()) );
  Content_Ptr->SetContent( UnNormalValue(Content.c_str()) );

  Tag_Ptr->Attr_List->ResetPT(toHead);
  for(Smart_Ptr<TagAttr> TagAttr_Ptr = (*(Tag_Ptr->Attr_List))++; TagAttr_Ptr.isNULL() != true; TagAttr_Ptr = (*(Tag_Ptr->Attr_List))++)
    Content_Ptr->SetAttr( UnNormalValue(TagAttr_Ptr->Value.c_str()),  UnNormalName(TagAttr_Ptr->AttrName.c_str()) );
}

void cxxlFASTCALL XmlStrReader::NewSubNode(cxxlXml_Node *ParentNode, const Smart_Ptr<Tag> &Tag_Ptr, wstring NoNameContent)
{
  Smart_Ptr<cxxlXml_Node> Node_Ptr = CreateSubNode(ParentNode, Tag_Ptr);

  AddNoNameContent(Node_Ptr, NoNameContent);
  NewSubNodeOrContent(Node_Ptr);
  if(this->isError())
  {
    err = true;
    return;
  }

  wstring EndTagName = L"</" + Tag_Ptr->TagName;
  const wchar_t *Sh[] = {L"<!--",EndTagName.c_str(),L"<",NULL};
  //wstring NoNameContent;
  NoNameContent.clear();

  while(true)
  {
    cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);

    if(R.Token.isNULL() )
    {
      err = true;
      return;
    }

    NoNameContent += R.SubStr;

    if(R.Token == L"<!--")
    {
      const wchar_t *Sh[] = {L"-->",NULL};
      cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);
      if(R.Token.isNULL())
      {
        err = true;
        return;
      }
    }
    else if(R.Token == EndTagName.c_str())
    {
      AddNoNameContent(Node_Ptr, NoNameContent);
      const wchar_t *Sh[] = {L">",NULL};
      SkipSpace(Wcspbrk);
      cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);
      if(R.Token.isNULL() || R.SubStr.StrLength() > 0)
        err = true;

      return;
    }
    else if(R.Token == L"<")
    {
      AddNoNameContent(Node_Ptr, NoNameContent);
      NoNameContent.clear();
      NewSubNodeOrContent(Node_Ptr);
      if(this->isError())
        return;
    }

  }
}

Smart_Ptr<cxxlXml_Node> cxxlFASTCALL XmlStrReader::CreateSubNode(cxxlXml_Node *ParentNode, const Smart_Ptr<Tag> &Tag_Ptr)
{
  Smart_Ptr<cxxlXml_Node> Node_Ptr =
    ParentNode->AddNode( UnNormalName(Tag_Ptr->TagName.c_str()) );

  Tag_Ptr->Attr_List->ResetPT(toHead);
  for(Smart_Ptr<TagAttr> TagAttr_Ptr = (*(Tag_Ptr->Attr_List))++; TagAttr_Ptr.isNULL() != true; TagAttr_Ptr = (*(Tag_Ptr->Attr_List))++)
    Node_Ptr->SetAttr( UnNormalValue(TagAttr_Ptr->Value.c_str()),  UnNormalName(TagAttr_Ptr->AttrName.c_str()) );

  return Node_Ptr;
}

void cxxlFASTCALL XmlStrReader::NewSubNodeOrContent(cxxlXml_Node *ParentNode)
{
  Smart_Ptr<Tag> Tag_Ptr = CatchTag();
  if(this->isError())
    return;

  if(Tag_Ptr->isCloseEnd)
  {
    CreateSubNode(ParentNode, Tag_Ptr);
    return;
  }

  wstring EndTagName = L"</" + Tag_Ptr->TagName;
  const wchar_t *Sh[] = {L"<!--",EndTagName.c_str(),L"<",NULL};

  wstring Content;

  while(true)
  {
    cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);

    Content += R.SubStr;

    if(R.Token.isNULL())
    {
      err = true;
      return;
    }
    else if(R.Token == L"<!--")
    {
      const wchar_t *Sh[] = {L"-->",NULL};
      cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);
      if(R.Token.isNULL())
      {
        err = true;
        return;
      }
    }
    else if(R.Token == L"<")
    {
      NewSubNode(ParentNode, Tag_Ptr, Content);
      return;
    }
    else
    {
      NewSubContent(ParentNode, Tag_Ptr, Content);
      return;
    }
  }
}

Smart_Ptr<cxxlXml_Node> cxxlFASTCALL XmlStrReader::CV()
{
  root_filter();
  if(this->isError())
    return NULL;

  Smart_Ptr<Tag> Tag_Ptr = CatchTag();
  if(this->isError())
    return NULL;

  Smart_Ptr<cxxlXml_Node> root_Ptr(new cxxlXml_Node(UnNormalName(Tag_Ptr->TagName.c_str()), this->GetSpirit()));
  Tag_Ptr->Attr_List->ResetPT(toHead);
  for(Smart_Ptr<TagAttr> TagAttr_Ptr = (*(Tag_Ptr->Attr_List))++; TagAttr_Ptr.isNULL() != true; TagAttr_Ptr = (*(Tag_Ptr->Attr_List))++)
    root_Ptr->SetAttr( UnNormalValue( TagAttr_Ptr->Value.c_str() ), UnNormalName(TagAttr_Ptr->AttrName.c_str()) );

  if(Tag_Ptr->isCloseEnd)
    return root_Ptr;

  wstring EndTagName = L"</" + Tag_Ptr->TagName;
  const wchar_t *Sh[] = {L"<!--",EndTagName.c_str(),L"<",NULL};

  wstring NoNameContent;

  while(true)
  {
    cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);

    if(R.Token.isNULL() )
      return NULL;

    NoNameContent += R.SubStr;

    if(R.Token == L"<!--")
    {
      const wchar_t *Sh[] = {L"-->",NULL};
      cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);
      if(R.Token.isNULL())
        return NULL;

      //continue;
    }
    else if(R.Token == EndTagName.c_str())
    {
      AddNoNameContent(root_Ptr, NoNameContent);
      const wchar_t *Sh[] = {L">",NULL};
      SkipSpace(Wcspbrk);
      cxxlWcspbrk_Result R = Wcspbrk.Next(Sh);
      if(R.Token.isNULL() || R.SubStr.StrLength() > 0)
        return NULL;

      return root_Ptr;
    }
    else if(R.Token == L"<")
    {
      AddNoNameContent(root_Ptr, NoNameContent);
      NoNameContent.clear();
      NewSubNodeOrContent(root_Ptr);
      if(this->isError())
        return NULL;
    }

  }
}


CXXL_DLLEXPORT Smart_Ptr<cxxlXml_Node> cxxlFASTCALL CxxlMan::ImportXML(wistream &XmlStr,ISpirit *spirit)
{
  XmlStrReader XSReader(XmlStr, spirit);

  return XSReader.CV();
}
